﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Xml.Linq;

using ApocDev.TownsApi.Aspects;

namespace ApocDev.TownsApi.XmlFiles
{
    [NotifyPropertyChanged]
    public class BuildingsXml : ObservableCollection<Building>, IChangedXml
    {
        // Unfortunately, this is one of those files where things have to be "specially" handled to allow
        // people to create their own things.
        public BuildingsXml(string actionsPath)
        {
            XElement root = XElement.Load(actionsPath);
            IEnumerable<XElement> elements = root.Elements();
            int total = elements.Count();
            ModFiles.FireLoadEvent(this, new FileLoadEventArgs("Buildings", total, 0));
            int numLoaded = 0;
            foreach (XElement xml in elements)
            {
                Add(new Building(xml));
                ModFiles.FireLoadEvent(this, new FileLoadEventArgs("Buildings", total, ++numLoaded));
            }
        }

        public bool IsDirty { get { return this.Any(a => a.IsDirty); } }

        public XElement SaveDirty()
        {
            if (!IsDirty)
                return null;
            var actions = new XElement("buildings");
            foreach (Building a in this)
            {
                if (a.IsDirty)
                    actions.Add(a.Save());
            }
            return actions;
        }

        public XElement Save()
        {
            var actions = new XElement("buildings");
            foreach (Building a in this)
            {
                actions.Add(a.Save());
            }
            return actions;
        }
    }

    [NotifyPropertyChanged]
    public class Building : IChangedXml
    {
        private readonly int _cleanHash;

        public Building(XElement xml)
        {
            MustBeBuiltOver = new ObservableCollection<Terrain>();
            Prerequistites = new ObservableCollection<Item>();
            PrerequisiteFriendly = new ObservableCollection<LivingEntity>();

            // This is default to true for basically everything.
            // Should only be false if we're specifically saying "you can't do this underground!"
            CanBeBuiltUnderground = true;

            ID = xml.Name.LocalName;
            foreach (XElement e in xml.Elements())
            {
                switch (e.Name.LocalName.ToLower())
                {
                    case "name":
                        Name = e.Value;
                        break;
                    case "width":
                        Width = int.Parse(e.Value);
                        break;
                    case "height":
                        Height = int.Parse(e.Value);
                        break;
                    case "description":
                        Description = e.Value;
                        break;
                    case "grounddata":
                        GroundData = e.Value;
                        break;
                    case "canbebuiltunderground":
                        CanBeBuiltUnderground = e.Value.ToLower() != "false";
                        break;
                    case "mustbebuiltover":
                        MustBeBuiltOver.Add(ModFiles.GetTerrain(e.Value));
                        break;
                    case "prerequisite":
                        Prerequistites.Add(ModFiles.GetItem(e.Value));
                        break;
                    case "prerequisitefriendly":
                        IEnumerable<string> valueList =
                            e.Value.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim());
                        foreach (string s in valueList)
                        {
                            PrerequisiteFriendly.Add(ModFiles.GetLivingEntity(s));
                        }
                        break;
                    case "type":
                        Type = e.Value;
                        break;
                    case "automatic":
                        Automatic = e.Value.ToLower() == "true";
                        break;
                    case "mineterrain":
                        MineTerrain = e.Value.ToLower() == "true";
                        break;
                    default:
                        MessageBox.Show("Unknown element for " + GetType().Name + ": " + e.Name.LocalName);
                        break;
                }
            }
            _cleanHash = GetHashCode();
        }

        public string ID { get; set; }

        public string Name { get; set; }
        public string Description { get; set; }

        public int Width { get; set; }
        public int Height { get; set; }

        public string GroundData { get; set; }
        public string Type { get; set; }
        public bool Automatic { get; set; }

        public bool CanBeBuiltUnderground { get; set; }
        public bool MineTerrain { get; set; }

        public ObservableCollection<Terrain> MustBeBuiltOver { get; set; }
        public ObservableCollection<Item> Prerequistites { get; set; }
        public ObservableCollection<LivingEntity> PrerequisiteFriendly { get; set; }

        public bool IsDirty { get { return _cleanHash != GetHashCode(); } }

        public XElement Save()
        {
            var root = new XElement(ID,
                new XElement("name", Name),
                Xml.AddIf("description", Description),
                new XElement("groundData", GroundData),
                Xml.AddIf("width", Width),
                Xml.AddIf("height", Height),
                // Default value for CanBeBuiltUnderground is true.
                Xml.AddIf("canBeBuiltUnderground", CanBeBuiltUnderground, true),
                Xml.AddIf("automatic", Automatic),
                Xml.AddIf("mineTerrain", MineTerrain));

            // No Xml.AddIf's for these!
            foreach (Terrain terrain in MustBeBuiltOver)
            {
                root.Add(new XElement("mustBeBuiltOver", terrain.ID));
            }

            foreach (Item prerequistite in Prerequistites)
            {
                root.Add(new XElement("prerequisite", prerequistite.ID));
            }

            foreach (LivingEntity livingEntity in PrerequisiteFriendly)
            {
                root.Add(new XElement("asdf", livingEntity.ID));
            }

            return root;
        }

        public XElement SaveDirty()
        {
            return Save();
        }
    }
}